package eerbaar.client.internal.exp;

import java.util.ArrayList;
import java.util.List;

import eerbaar.client.exp.IScope;
import eerbaar.client.exp.IState;
import eerbaar.client.exp.ScopeManager;
import eerbaar.shared.tree.INode;
import eerbaar.shared.tree.NodeCmdFactory;
import eerbaar.shared.tree.NodeFactory;

public class Scope implements IScope {

    private final List<Scope> children = new ArrayList<Scope>();
    private final ScopeManager manager;
    private final String name;
    private final IScope parent;
    private final State state = new State();
    private Object target;
    private Object game;
    private Object valueArea;

    public Scope(ScopeManager manager, IScope parent, String name) {

        this.manager = manager;
        this.parent = parent;
        this.name = name;
        if (parent != null) {
            this.target = parent.getTarget();
            this.game = parent.getGame();
        }
    }

    public Scope(ScopeManager manager, String name) {

        this(manager, null, name);
    }

    public void addChild(String inName) {

        Scope child = new Scope(this.manager, inName);
        this.children.add(child);
    }

    @Override
    public boolean equals(Object obj) {

        if (this == obj) {
            return true;
        }

        if (obj == null) {
            return false;
        }

        Scope other = (Scope) obj;
        if (!this.name.equals(other.name)) {
            return false;
        }

        return true;
    }

    public int getDepth() {

        int result = 0;
        IScope temp = this;
        while (temp != null) {
            result++;
            temp = temp.getParent();
        }

        return result;
    }

    @Override
    public Object getGame() {
        return game;
    }

    public ScopeManager getManager() {

        return this.manager;
    }

    @Override
    public String getName() {

        return this.name;
    }

    @Override
    public IScope getParent() {

        return this.parent;
    }

    @Override
    public String getPath() {

        String s = "";
        IScope temp = this;
        while (temp != null) {
            s = temp.getName() + "/" + s;
            temp = temp.getParent();
        }
        s = "/" + s;

        return s;
    }

    @Override
    public ScopeManager getScopeManager() {
        return this.manager;
    }

    @Override
    public IState getState() {

        return this.state;
    }

    @Override
    public Object getTarget() {
        return this.target;
    }

    @Override
    public Object getValueArea() {

        return this.valueArea;
    }

    @Override
    public int hashCode() {

        return this.name.hashCode();
    }

    @Override
    public void load(INode node) {

        INode child = NodeCmdFactory.findChild(node, this.name);
        if (child == null) {

            child = NodeFactory.create(this.name);
            NodeCmdFactory.add(node, child);
        }

        this.state.load(child);
    }

    private String pad() {

        String s = "";
        int depth = getDepth();
        for (int i = 1; i < depth; i++) {
            s += "    ";
        }

        return s;
    }

    public void removeChild(String inName) {

        Scope child = new Scope(this.manager, inName);
        this.children.remove(child);
    }

    @Override
    public void save(INode node) {

        INode child = NodeCmdFactory.findChild(node, this.name);
        if (child == null) {

            child = NodeFactory.create(this.name);
            NodeCmdFactory.add(node, child);
        }

        this.state.save(child);
    }

    @Override
    public void setGame(Object game) {
        this.game = game;
    }

    @Override
    public void setTarget(Object target) {
        this.target = target;
    }

    @Override
    public void setValueArea(Object area) {

        this.valueArea = area;
    }

    @Override
    public String toString() {

        final String PAD = pad();

        String s = PAD;
        s += this.name + " ";
        s += this.state;
        s += "\n";

        List<Scope> children1 = new ArrayList<Scope>();
        for (Scope scope : children1) {
            s += scope.toString();
        }
        s += '\n';

        return s;
    }

}
